//===============================================================================
// Microsoft patterns & practices
// Web Client Software Factory
//-------------------------------------------------------------------------------
// Copyright (C) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//-------------------------------------------------------------------------------
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================
using System;
using System.Collections;
using System.Collections.Generic;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
using WCSFContrib.PageFlow.WorkflowFoundation.Properties;
using WCSFContrib.PageFlow.Utils;

namespace WCSFContrib.PageFlow.WorkflowFoundation
{
	/// <summary>
    /// Implementation of the page flow state that uses Windows Workflow Foundation as the persistence store.
	/// </summary>
    [Serializable]    
	public class WorkflowFoundationPageFlowState : PageFlowState
	{
		[NonSerialized] private WorkflowInstance _instance;

        /// <summary>
        /// Initializes a new instance of the <see cref="WorkflowFoundationPageFlowState" /> class.
        /// </summary>
        /// <param name="instance">The workflow instance where the state will be stored</param>
		public WorkflowFoundationPageFlowState(WorkflowInstance instance)
		{
			Guard.ArgumentNotNull(instance, "instance");
			_instance = instance;
		}

        /// <summary>
        /// Gets the collection of state keys
        /// </summary>
		public override ICollection Keys
		{
			get
			{
				DataExchangeServiceInstance.Keys(_instance.InstanceId);
				RunWorkflow();
				return WorkflowDataAdapter.Instance.GetKeys(_instance.InstanceId);
			}
		}

        /// <summary>
        /// Gets or sets an object from the state
        /// </summary>
        /// <param name="key">The key that identifies the state object</param>
        /// <returns>The object</returns>
        /// <remarks>
        /// <para>The object must be marked with the <see cref="SerializableAttribute">[Serializable]</see> attribute</para>
        /// </remarks>
        /// <exception cref="ArgumentNullException"><paramref name="key"/> is <see langword="null"/></exception>
        /// <exception cref="ArgumentException"><paramref name="key"/> does not exists</exception>
        public override object this[string key]
		{
			get
			{
				if (string.IsNullOrEmpty(key))
					throw new ArgumentNullException("key");

				if (!Contains(key))
					throw new ArgumentException(Resources.PageFlowStateEntryDoenstExist);

				return Get(key);
			}
			set
			{
				if (string.IsNullOrEmpty(key))
					throw new ArgumentNullException("key");

				Set(key, value);
			}
		}

        /// <summary>
        /// Returns true if the key exists
        /// </summary>
        /// <param name="key">The key</param>
        /// <returns>True if the key exists</returns>
        /// <exception cref="ArgumentNullException"><paramref name="key"/> is <see langword="null"/></exception>
		public override bool Contains(string key)
		{
			if (string.IsNullOrEmpty(key))
				throw new ArgumentNullException("key");

			return !(Get(key) == null);
		}

        /// <summary>
        /// Removes a state object from the state given its key
        /// </summary>
        /// <param name="key">The key</param>
        /// <exception cref="ArgumentNullException"><paramref name="key"/> is <see langword="null"/></exception>		
		public override void Remove(string key)
		{
			if (string.IsNullOrEmpty(key))
				throw new ArgumentNullException("key");

			DataExchangeServiceInstance.Remove(_instance.InstanceId, key);
		}

		private object Get(string key)
		{
			DataExchangeServiceInstance.Get(_instance.InstanceId, key);
			RunWorkflow();
			return WorkflowDataAdapter.Instance.GetData(_instance.InstanceId);
		}

		private void Set(string key, object value)
		{
			DataExchangeServiceInstance.Set(_instance.InstanceId, key, value);
			RunWorkflow();
		}

		private void RunWorkflow()
		{
			WorkflowRuntime runtime = _instance.WorkflowRuntime;
			ManualWorkflowSchedulerService scheduler = runtime.GetService<ManualWorkflowSchedulerService>();
			scheduler.RunWorkflow(_instance.InstanceId);
		}

		private DataExchangeService DataExchangeServiceInstance
		{
			get { return _instance.WorkflowRuntime.GetService<DataExchangeService>(); }
		}
	}
}
